csshtmlsvghtml-lists

How can I make a list-style-image scale with the list's font size, when we can't use glyph fonts?


A webpage I'm working on uses some fancy chevrons for bullet points in a list. I'd like to define a list style that scales with the font size of the list items itself: doing so is the ultimate end goal of my problem here.

We currently keep those chevrons in SVG files (one of which is offered below) so they can be magnified without looking terrible. They're referenced like this:

ul.foo {
    list-style-image: url("../images/chevron.svg");
}

We use these chevron lists a few times each around the site. Sometimes they're with large text, sometimes with smaller or normal sized text. We're forced to create a new chevron image for each font size (e.g. chevron-small.svg, chevron-medium.svg, chevron-large.svg, etc), but surely there's a better way that lets us use just the one image and have it scaled up and down on its own based on the font size!

However, I haven't figured out how to make the image scale with the font size yet.

The W3 wiki for list-style-image suggests that "if the image's intrinsic width or height is given as a percentage, then that percentage is resolved against 1em", which sounds like it's exactly what we want. I haven't worked out how to make this happen though. Brian Campbell's answer to How can I make an svg scale with its parent container? appears to suggest a way to make this percentage thing happen, but when I set a width or height of 100%, the chevron bullet points show up extremely tiny or not at all, even when the font size is large.

How can I make this list-style-image scale fully with the text size, so that as a UL's text size gets larger, the bullet image does too?

(Glyph fonts: We can't use them. They'd get the job done visually, but they have a bad impact on accessibility because screen readers won't read out the bullets as bullets but as some other weird character. We could define a custom glyph font, possibly, and replace the bullet characters in it with ours, but the file size overhead in doing so would be excessive. As far as I can tell, we need to use an image.)

My SVG's code

The SVG comes from Illustrator and has this code:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="8px" height="14px" viewBox="0 0 8 14" enable-background="new 0 0 8 14" xml:space="preserve">
<path fill="#666666" d="M0.37,12.638l5.726-5.565L0.531,1.347C0.252,1.059,0.261,0.601,0.547,0.321
    c0.289-0.279,0.746-0.272,1.026,0.016l6.062,6.24c0,0.002,0.006,0.004,0.008,0.006c0.068,0.07,0.119,0.156,0.156,0.244
    C7.902,7.088,7.846,7.399,7.631,7.61c-0.002,0.004-0.006,0.004-0.01,0.006l-6.238,6.063c-0.143,0.141-0.331,0.209-0.514,0.205
    c-0.187-0.006-0.372-0.078-0.511-0.221C0.076,13.376,0.083,12.919,0.37,12.638"/>
</svg>

Which shows up like the following, where the text is 16px, and the chevron isn't scaling to font size, but is decently large and visible (a bit larger than desired in this case, but let's ignore that, since the image itself can be edited):

As I stated, I tried to follow Brian Campbell's answer and set the width or height property to 100%:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="100%" viewBox="0 0 8 14" enable-background="new 0 0 8 14" xml:space="preserve">

However, having either width or height defined as 100% seems to make the chevrons tiny, and much smaller than 1em, as stated:

(Screenshot from Firefox. In Chrome they're a little bit bigger, still far smaller than 16px.)

Code snippet

/* 
The image referenced here is the SVG provided above, with base 64 encoding. It is the
freshly exported version that still has a defined width and height of 8px and 14px.
You may wish to just save the SVG above locally.
*/

ul {
  list-style-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI4cHgiIGhlaWdodD0iMTRweCIgdmlld0JveD0iMCAwIDggMTQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDggMTQiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiM2NjY2NjYiIGQ9Ik0wLjM3LDEyLjYzOGw1LjcyNi01LjU2NUwwLjUzMSwxLjM0N0MwLjI1MiwxLjA1OSwwLjI2MSwwLjYwMSwwLjU0NywwLjMyMWMwLjI4OS0wLjI3OSwwLjc0Ni0wLjI3MiwxLjAyNiwwLjAxNmw2LjA2Miw2LjI0YzAsMC4wMDIsMC4wMDYsMC4wMDQsMC4wMDgsMC4wMDZjMC4wNjgsMC4wNywwLjExOSwwLjE1NiwwLjE1NiwwLjI0NEM3LjkwMiw3LjA4OCw3Ljg0Niw3LjM5OSw3LjYzMSw3LjYxYy0wLjAwMiwwLjAwNC0wLjAwNiwwLjAwNC0wLjAxLDAuMDA2bC02LjIzOCw2LjA2M2MtMC4xNDMsMC4xNDEtMC4zMzEsMC4yMDktMC41MTQsMC4yMDVjLTAuMTg3LTAuMDA2LTAuMzcyLTAuMDc4LTAuNTExLTAuMjIxQzAuMDc2LDEzLjM3NiwwLjA4MywxMi45MTksMC4zNywxMi42MzgiLz48L3N2Zz4=');
  /* Or if you wish to save the SVG locally:
  list-style-image: url('chevron.svg');
  */
}

.small-list {
   font-size: 85%;
}

.large-list {
  font-size: 150%;
}
<ul class="small-list">
  <li>The goal is to make the chevron smaller for this list</li>
  <li>Specifically, just slightly smaller than capital letters, as stated.</li>
  <li>Nomas matas</li>
  <li>Roris dedit</li>
</ul>

<ul class="large-list">
  <li>And larger for this list</li>
  <li>Nomas matas</li>
  <li>Roris dedit</li>
</ul>


Solution

  • I would approach solving this problem using a pseudo element before each li

    Here is the markup

    ul {
        list-style: none;
    }
    
    li {
        position: relative;
    }
    
    li:before {
        /*
        The desired width gets defined in two places: The element width, and background size.
        The height only gets defined once, in background size.
        */
        position: absolute;
        display: block;
        content: '\2022'; /* bullet point, for screen readers */
        text-indent: -999999px; /* move the bullet point out of sight */
        left: -.75em;
        width: .4em; /* desired width of the image */
        height: 1em; /* unrelated to image height; this is so it gets snipped */
        background-repeat: no-repeat;
        background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI4cHgiIGhlaWdodD0iMTRweCIgdmlld0JveD0iMCAwIDggMTQiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDggMTQiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiM2NjY2NjYiIGQ9Ik0wLjM3LDEyLjYzOGw1LjcyNi01LjU2NUwwLjUzMSwxLjM0N0MwLjI1MiwxLjA1OSwwLjI2MSwwLjYwMSwwLjU0NywwLjMyMWMwLjI4OS0wLjI3OSwwLjc0Ni0wLjI3MiwxLjAyNiwwLjAxNmw2LjA2Miw2LjI0YzAsMC4wMDIsMC4wMDYsMC4wMDQsMC4wMDgsMC4wMDZjMC4wNjgsMC4wNywwLjExOSwwLjE1NiwwLjE1NiwwLjI0NEM3LjkwMiw3LjA4OCw3Ljg0Niw3LjM5OSw3LjYzMSw3LjYxYy0wLjAwMiwwLjAwNC0wLjAwNiwwLjAwNC0wLjAxLDAuMDA2bC02LjIzOCw2LjA2M2MtMC4xNDMsMC4xNDEtMC4zMzEsMC4yMDktMC41MTQsMC4yMDVjLTAuMTg3LTAuMDA2LTAuMzcyLTAuMDc4LTAuNTExLTAuMjIxQzAuMDc2LDEzLjM3NiwwLjA4MywxMi45MTksMC4zNywxMi42MzgiLz48L3N2Zz4=');
        background-size: .4em .7em;
        background-position: 0 .3em;
    }
    
    .small-list {
        font-size: 85%;
    }
    
    .large-list {
        font-size: 150%;
    }
    <ul class="small-list">
      <li>The goal is to make the chevron smaller for this list</li>
      <li>Specifically, just slightly smaller than capital letters, as stated.</li>
      <li>Nomas matas</li>
      <li>Roris dedit</li>
    </ul>
        
    <ul class="large-list">
      <li>And larger for this list</li>
      <li>Multiline list item<br>for testing</li>
      <li>Nomas matas</li>
      <li>Roris dedit</li>
    </ul>

    Explanation:

    Caveat: - IE 8 doesn't support background-size, but I presume that this will not be an issue as it also doesn't support rendering svg.