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

Adds an option to disable moving tethered element to the body #96

Closed

Conversation

pzuraq
Copy link

@pzuraq pzuraq commented Jul 10, 2015

Updated version of #84, with version bump to signal new feature.

@zackbloom
Copy link
Contributor

I'm not really sure I understand how tether can work without moving elements into the body. The basic premise is that it positions it's element absolutely, usually relative to the body. There are specific cases where it can position relative to a parent element instead, but you are not forcing it to use that mode (https://github.com/pzuraq/tether/blob/add-option-to-disable-move-element/src/js/tether.js#L715-L726).

If you apply this change, and any of the tethered elements parents are not position: static, the positioning will become erratic and incorrect. I would suggest you create a file with a test case to get an idea of the problem, and then look into forcing tether to use either fixed positioning (which is always relative to the viewport) or offset parent relative positioning (that link above) in that case.

@pzuraq
Copy link
Author

pzuraq commented Jul 15, 2015

@zackbloom Thanks for the quick response! Completely understand, and at first it does seem a little counterintuitive but ultimately we are trying to position relative to the body, just a couple elements deeper. The HTML structure looks something like this:

<body>
    <div id="animation-container">
        <div class="tethered-element"></div>
    </div>

    <div>
        <!-- Rest of the application -->
    </div> 
</body>
#animation-container {
    position: absolute;
    top: 0;
    left: 0;
}

If the tether is attached to #animation-container, anything positioned relative to it will also effectively be positioned relative to the document body. Note that in this case, the element will still be moved to the body since offset.top === offset.left === 0, thus failing the checks.

Being able to attach and remove tether's to specific elements allows us to encapsulate our animation logic in other web components. Ember in particular makes use of the liquid-fire library, which uses components to control animation. If we can't control the root the tethered objects are appended to, it will be much more difficult for us to animate smoothly, which is why we'd like this feature. It's understandable if you still think it's outside of the scope of Tether.js though.

@zackbloom
Copy link
Contributor

I understand, but this code doesn't enforce the invariant that no parent of the element is positioned. I would suggest that rather than using an option, you instead iterate through the elements parents, and if they are all position: static, don't do the repositioning.

@pzuraq
Copy link
Author

pzuraq commented Jul 15, 2015

@zackbloom That sounds like an excellent idea! Will close this PR and submit a new one with that behavior instead.

@pzuraq pzuraq closed this Jul 15, 2015
@pzuraq pzuraq deleted the add-option-to-disable-move-element branch July 15, 2015 18:13
@pzuraq pzuraq restored the add-option-to-disable-move-element branch July 15, 2015 21:37
@marcoow
Copy link

marcoow commented Jul 21, 2015

There's another case where having an option to define a different parent element would be extremely helpful and that's testing Ember applications. In testing the Ember app typically renders the whole application into an element somewhere below the body (usually sth. like #ember-testing-container) which then also defines the scope for events that Ember is listening to. When you have events fired from elements that are inside a component that tether is used on and that'a thus moved out of the testing container and below the body these events would never be handled then.

In that case it would be really nice if we could limit tether to the testing container. Our current quick fix is to simply not use tether in testing mode but that doesn't really seem so nice.

@pzuraq
Copy link
Author

pzuraq commented Jul 21, 2015

@marcoow I'm getting around this at the moment by setting the positioning of the testing container to static instead of relative. There don't appear to be any differences in performance, though I suppose absolutely positioned elements which are not tethers could experience glitches. For unit tests it is probably a solid strategy, though I agree it's not ideal.

@marcoow
Copy link

marcoow commented Jul 21, 2015

The problem I'm having isn't really that positioning is wrong or so but the fact that tether moves the positioned element under the <body> but I would need it under my #ember-testing-container element. I don't actually care much about correct positioning in my tests at all.

@pzuraq
Copy link
Author

pzuraq commented Jul 21, 2015

@marcoow Yes, and if you set the testing container to position: static the body will be the relative parent. With the latest version of tether that was just released, if this is the case then the tethered element will not be moved.

It's somewhat hack-y, and may cause other side-effects due to a lack of relative positioning for the rest of the container, but the tether element isn't moved which means that it still acts as normal in the body.

@marcoow
Copy link

marcoow commented Jul 21, 2015

I'm not actually talking about the positional parent element but about the actual parent element in the DOM. Tether actually moves the element in the DOM which results in problem for me.

@pzuraq
Copy link
Author

pzuraq commented Jul 21, 2015

@marcoow Yes, I know. I am talking about the PR I just made that prevents tether from doing that if the positional parent is the body.

@marcoow
Copy link

marcoow commented Jul 21, 2015

ah, sorry - didn't get that ;)

@pzuraq
Copy link
Author

pzuraq commented Jul 21, 2015

No worries! Two different types of positioning, hard to differentiate them semantically, totally understand :)

@varblob
Copy link

varblob commented Aug 26, 2015

@pzuraq I maybe understanding this wrong but after looking through the code / trying it out it seems like all elements between the body and the tethered element must be statically positioned in the current implementation as opposed to exit as soon as you hit one statically positioned element. Is this correct?

@pzuraq
Copy link
Author

pzuraq commented Aug 26, 2015

@varblob yep, that is correct. The Hubspot team didn't want to invalidate their rule, which is that the tethered element is positioned with respect to the body.

Personally, having worked with this for a while, I still think that it would make sense to add the option to allow users to manually override this behavior. We're encountering a lot of edge cases regarding z-index and testing containers (which are positioned relatively) which are breaking our apps, and we've had to cobble together some ugly hacks to make everything play nice.

@zackbloom I'd like you to reconsider adding this option. Users will still have to opt-out of tether's default behavior, and the majority of users will not. For those of us who have good reason to opt-out, we know (and accept) the potentially disastrous consequences. It would make life in the Ember world a lot easier (and I imagine the same goes for React and other frameworks).

@zackbloom
Copy link
Contributor

@pzuraq Why is #98 not sufficient?

@pzuraq
Copy link
Author

pzuraq commented Aug 26, 2015

For the library I'm developing we create two roots, one for the application and one for tethered elements:

<body>
  <div class="tether-container">
    <div class="animation-container">
      <div class="tethered-element"></div>
    </div>
  </div>

  <div class="ember-application">
    ...
  </div>
</body>

The tether container and animation container elements are web-components that manage the actual animation of tether, using the standard Ember animation library Liquid Fire. Note that we are guaranteed that positioning will be relative to the document, as the tether and animation containers are not offset from the document in any way.

There are two major issues that have popped up because we can't put tethered elements inside of absolute, relative, or fixed position elements:

  • z-index. Because the tethered elements are not at the actual root, they will often times be below the z-index of other elements in the application body. We cannot fix this by enclosing the elements with a relatively positioned container that has a high z-index. This has resulted in the following (terrible) CSS hack:
.tether-container * {
    z-index: 9999;
}
  • Testing. Ember embeds the application in a relatively positioned element during tests by default, which throws tethered elements outside the scope of the Ember app and causes things to fail. I'm sure this could become a problem in other CI testing frameworks.

Like I said we were able to get around both of these issues, and the current functionality works for the most part, but I believe these are just the first of many potential edge cases that will popup because we cannot manually control the DOM behavior of tethered elements

@ghost
Copy link

ghost commented May 12, 2016

This is what I currently use to workaround the difficulties of testing tether with ember: yapplabs/ember-tether#33

@pzuraq
Copy link
Author

pzuraq commented May 16, 2016

@martndemus That works for testing purposes, but for the z-index issue it doesn't do anything unfortunately. This is really one of the fundamental differences between liquid-tether and ember-tether, liquid-tether has to manage positioning of tethered elements in the DOM in order to facilitate the animations.

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

Successfully merging this pull request may close these issues.

None yet

4 participants