Search code examples
htmlcsssvgcss-positionbackground-image

CSS: Load SVG and position relative to its elements


In the spirit of http://www.csszengarden.com/, I want to see how far I can go with css only in this situation.

I am given an html page with the following list which I can style however I want using a css file, but not modify. The text of the items is not known in advance.

<ul>
    <li id="item1">You</li>
    <li id="item2">Can</li>
    <li id="item3">Call</li>
    <li id="item4">Me</li>
    <li id="item5">Al</li>
</ul>

I also have this separate SVG file (view in jsfiddle):

<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"
     viewBox="0 0 800 600" enable-background="new 0 0 800 600" xml:space="preserve">
<path fill="none" stroke="#000000" stroke-width="22" stroke-miterlimit="10" d="M64.5,381.5c232-235,365-321,335-152
    s-152,145-101,1s265-105,241-5s-68,342-159,258s142-211,164-70s191-83,191-83"/>
<circle id="circle1" fill="#FFFFFF" stroke="#FF0000" stroke-width="22" stroke-miterlimit="10" cx="131" cy="323" r="23"/>
<circle id="circle2" fill="#FFFFFF" stroke="#FF0000" stroke-width="22" stroke-miterlimit="10" cx="290" cy="288" r="23"/>
<circle id="circle3" fill="#FFFFFF" stroke="#FF0000" stroke-width="22" stroke-miterlimit="10" cx="528" cy="272" r="23"/>
<circle id="circle4" fill="#FFFFFF" stroke="#FF0000" stroke-width="22" stroke-miterlimit="10" cx="383" cy="487" r="23"/>
<circle id="circle5" fill="#FFFFFF" stroke="#FF0000" stroke-width="22" stroke-miterlimit="10" cx="698" cy="375" r="23"/>
</svg>

In my CSS file, I want to load the SVG and style the list like so: each text on a circle

Basically, positioning #item1 relative to #circle1, #item2 relative to #circle2 and so on (truly relative, without hardcoding the item positions).

I haven't found a way to both load an SVG and have its elements accessible only via CSS. Can this be done?


Solution

  • Unfortunately, CSS doesn't allow referencing dynamic properties like positions from unrelated elements.

    You can achieve that with JavaScript:

    1. First, check the relative position of each circle
    const circle1 = document.querySelector('#circle1');
    const { offsetLeft, offsetTop } = circle1;
    
    1. Then, set those coordinates to the top and left values of these offsets:
    const label1 = document.querySelector('#item1');
    label1.style.position = 'absolute';
    label1.style.left = `${offsetLeft}px`;
    label1.style.top = `${offsetTop}px`;
    

    In case getting the offset doesn't work with plain JS and your SVG, consider using a 3rd party library (like jQuery) or reading the cx and cy attributes directly from the <circle> element.