lukePeavey / SplitType

Javascript utility that splits text into lines, words, characters for animation
https://lukepeavey.github.io/SplitType/
545 stars 39 forks source link

only set nested html elements to relative if needed #55

Open eballeste opened 1 year ago

eballeste commented 1 year ago

I have a global script that automatically adds a dynamic button to headline texts based on whether a nested span element within the headline has a specific target class. This dynamically inserted button is absolutely positioned relative to the span element.

Example markup:

  <h2>Text that is split and I want to add a legal disclaimer button <span class="js-legal-text">to</span>.</h2>

Example markup after my script runs:

  <h2>Text that is split and I want to add a legal disclaimer button <span class="js-legal-text">to <button>*</button></span>.</h2>

My script works beautifully except for animated headlines that use the splittype library. An extra space is added in between my button and the span wrapped text. After digging into it I noticed that it was this SplitType library that changes my button from an absolute to a relative positioned button. I tried using the absolute: true setting but this just breaks the layout even more since SplitType then injects more style attributes to the button which causes even more conflicts with my style rules from my original script.

I was wondering would it be possible to modify SplitType so that it does a check for any inline styles before forcing the div to be relatively positioned?

something like (untested pseudocode):

split.js

  ...

  if (!data.get(node).isRoot) {
      node.style.display = 'inline-block'

      if (isEmpty(node.style.position)) {
        node.style.position = 'relative'
      }

     ...
eballeste commented 1 year ago

as a workaround, im looking for mutations on my dynamically created buttons and reverting the style if the mutation is related to the style attribute

  ...
  const observer = new MutationObserver(function(mutations) {
    const relativeFound = false;

    mutations.forEach(function({oldValue, target}) {
      if (oldValue.includes('position: absolute') && target.style.position === 'relative') {
        $symbolButton.style.position = 'absolute';
        relativeFound = true;
      }
    });

    if (relativeFound) {
      observer.disconnect();
    }
  });

  observer.observe($symbolButton, { attributeOldValue: true });
  ...
lukePeavey commented 1 year ago

Would it be possible to create a codePen / CodeSandbox example of this issue?

eballeste commented 1 year ago

i can't at the moment because it's a pretty big project and extracting this specific part into a codepen would be time-consuming but my description above is pretty straightforward, your script is forcing all elements within the split text to be relatively positioned but i need only one of those elements to remain absolutely positioned which is why i can't use the "absolute: true" setting. this setting breaks my entire layout by adding even more inline css.

my proposed solution is to only add the inline position style to elements that don't already have one. ideally your script still adds the relative position rule but skips over any element that already has a different value.

my headlines start like this:

Headline Text & Asterisk

and end up like this where the asterisk is a button:

Headline Text & Asterisk*


Adding the inline styles to my examples so it's a little clearer?

headline before my script:

<h2>headline text & <span style="position: relative;">asterisk</span>.</h2>

headline after my script:

<h2>headline text & <span style="position: relative;">asterisk <button style="position: absolute;">*</button></span>.</h2>

headline after splittype is run:

<div style="overflow: hidden;">
  <div class="line">Headline text & </div>
</div>
<div style="overflow: hidden;">
  <div class="line">
    <span style="position: relative;">asterisk <button style="position: relative;">*</button></span>
  </div>
</div>
lukePeavey commented 9 months ago

@eballeste several other people have requested this. I am working on a PR that will make it possible to set the display or position of nested elements inside the target element.

Follow #69 for updates