Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to change defined ids for every time an svg is rendered? #98

Closed
jd1378 opened this issue Apr 11, 2023 · 5 comments
Closed

Comments

@jd1378
Copy link

jd1378 commented Apr 11, 2023

right now when loading a svg, the first time its loaded the gradients defined in it works fine
but when you load the same svg for the second time, it no longer renders correctly, as ids clash
I was wondering if we could prefix an incremental number to the svg ids used inside it every time its rendered

@gkatsanos
Copy link
Collaborator

@jd1378 we'll need a minimal reproduction link on https://stackblitz.com/ to help you out!

@gkatsanos
Copy link
Collaborator

gkatsanos commented May 8, 2023

@jd1378 solution to your problem: #94 (comment) more info: svg/svgo#674 (comment)

@jd1378
Copy link
Author

jd1378 commented May 9, 2023

@gkatsanos That, definitely is not the solution
It just solves the issue between different svgs
Not between the same svg being repeated multiple times

Anyway i solved this by extracting and injecting my defs to top of body when my svg is being loaded and skiped svgo for it

I don't think this is solvable easily (at the level of this library)

@DirectorRen-TV
Copy link

I also encountered this problem when using nuxt-svg-loader (one hell of a problem, it's the same).
There's one suggestion to solve this within a Vue instance: find and dynamically link all the id's within a component, add an increment to them, and store the global value in $root.
But this solution leads to the next step of the problem - the possibility of having more than one application instance on the same page: they will have independent incrementers, potentially causing overlap.

@jd1378
Copy link
Author

jd1378 commented May 10, 2023

well you can do what I did without any problem:

  1. optimize your svg manually, using the svgo or any website like vecta nano
  2. manually rename all ids to something unique
  3. remove defs from svg file (or anything that has id="" attribute)
  4. when your component is mounting (in vue.js onBeforeMount for example), check if any of ids you had in the defs exist in the dom (using document.getElementById), and if it doesn't inject it to the top of body (by creating an svg element and setting it's innerHTML to the defs). you have to inject it to the top or otherwise it won't work. this way you only inject it once. and only inject it when needed.
  5. apply position absolute, width 0 and height 0 for not affecting your page flow

here is an example:

onBeforeMount(() => {
  if (!document.getElementById('one-of-your-defs-ids')) {
    const fillDef = document.createElementNS(
      'http://www.w3.org/2000/svg',
      'svg',
    );
    fillDef.style.position = 'absolute';
    fillDef.style.width = '0';
    fillDef.style.height = '0';
    fillDef.innerHTML =
      '<defs><linearGradient id="one-of-your-defs-ids" x1="11.4857" y1="18.2663" x2="9.07356" y2="5.37942" gradientUnits="userSpaceOnUse"><stop stop-color="#f5953d"/><stop offset=".236" stop-color="#eb493a"/><stop offset="1" stop-color="#ffe82f"/></linearGradient></defs>';
    document.body.prepend(fillDef);
  }
});

I hope this does make it clear for anyone who finds this problem later :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants