barbajs / barba

Create badass, fluid and smooth transitions between your website’s pages
https://barba.js.org/
MIT License
11.6k stars 477 forks source link

Barba.js v2? Open discussion #41

Closed luruke closed 5 years ago

luruke commented 8 years ago

Hi All! I am really happy to see more and more people using Barba.js. It's really nice to be able to give something back to the open source community.

I am also proud that in ~20 issues opened from users, there is not a single bug that has been encountered.

The library has been initially used just from myself, but now we should look ahead and see how the library could be improved in a eventually major release.


I think the design and the concept behind the library seems working very well, it's flexible and it's easily adaptable to the user's need.

What I think could really be improved are how the API methods are exposed, and the naming in general.


Can you help me?

I would like to have an open discussion and see what are your ideas about it:

Thank you! 🎉

terion-name commented 8 years ago

Hi. Barba is cool ) But it leaks of better ES6 support (e.g. I can't extend base transtion) and docs are confusing in some places. For example: http://barbajs.org/transition.html

Barba.Pjax.getTransition = function() {
  /**
   * Here you can use your own logic!
   * For example you can use different Transition based on the current page or link...
   */
  return FadeTransition;
};

It is cool, but I really can't use different Transition based on the current link because I can't access it from there.

About limits — impossibility to have several updatable containers

luruke commented 8 years ago

Hello @terion-name !

  1. ES6 - Yep, you're right. I would like to give support for ES6 but at the same time I want the library to work good on older version of ecmascript. I haven't yet found a solution on how manage/run/extend classes on different ES versions. See https://github.com/luruke/barba.js/issues/39
  2. .getTransition - You have different ways decide what transition to use. I have identified three techniques. You can check my comment here for more information: https://github.com/luruke/barba.js/issues/19#issuecomment-223874845 - Definitely is something that could be explained better on the documentation
  3. The main concept of Barba.js is to create a fluid transition between pages, but each page needs to be served and accessible from its direct link. I can't see how multiple containers could be used, and I never had the need of it. Could you please make an example?

Many thanks for your feedbacks, I really appreciate it. Do not hesitate to make a pull request or to comment if you have further ideas / improvements. Cheers.

terion-name commented 8 years ago
  1. Babel?)
  2. Oh, awesome. This definitely should be be the docs =)
  3. I mean multiple parts of page to be updated. See: #27
terion-name commented 8 years ago

also:

luruke commented 8 years ago

Hello again @terion-name

  1. Babel - Yes, but then how do you extend ES6 classes in ES5? We can continue the conversation here https://github.com/luruke/barba.js/issues/39
  2. Multiple containers - It sounds something very specific that will make the setup more complex anyway. In all the websites I made using Barba.js I never had this need. Maybe I am missing something, would be really great if you could explain your idea better or maybe with a demo.
  3. Programmatically go to other pages - There is the method Barba.Pjax.goTo http://barbajs.org/docs/Barba.Pjax.html#.goTo
  4. How Barba.js should work in this case for you? Reload the current container with the transition?
terion-name commented 8 years ago
  1. went there
  2. it 100% depends on design. not all sites have some static and non-changable layout with a single container. yes, now I simply wrap entire body for this, but it would be great to have possibility to change some parts simultaniously. but yes, this is maybe not mandatory. swapping entire body for such cases works to, so maybe making things more complex not worth it.
  3. thank you, didn't find it in docs
  4. catch form submit, prevent it, create and submit FormData, reload container with response
terion-name commented 8 years ago

Oh, and redirects handling

terion-name commented 8 years ago

Redirects are easily handled if use fetch.

And about forms, here is a demo how I handle forms now (this is a bad code, but I've needed to make it work VERY quick), it also handles redirects:

    handleForms(e) {
        e.preventDefault();
        const url = e.target.getAttribute('action');
        const method = e.target.method || 'get';
        const formData = new FormData(e.target);
        fetch(url, {
            method: method,
            body: formData
        }).then(function (response) {
            response.text().then(function(data) {
                var newContainer = new Promise(function(resolve, reject) {
                    var container = Barba.Pjax.Dom.parseResponse(data);
                    Barba.Pjax.Dom.putContainer(container);
                    Barba.Pjax.History.add(response.url);
                    window.history.pushState({}, '', response.url);
                    setTimeout(resolve(container), 1);
                });

                var transition = Object.create(Barba.Pjax.getTransition());

                Barba.Pjax.transitionProgress = true;

                Barba.Dispatcher.trigger('initStateChange',
                    Barba.Pjax.History.currentStatus(),
                    Barba.Pjax.History.prevStatus()
                );

                var transitionInstance = transition.init(
                    Barba.Pjax.Dom.getContainer(),
                    newContainer
                );

                newContainer.then(
                    Barba.Pjax.onNewContainerLoaded.bind(Barba.Pjax)
                );

                transitionInstance.then(
                    Barba.Pjax.onTransitionEnd.bind(Barba.Pjax)
                );
            });
        });
    }
luruke commented 8 years ago

Thanks @terion-name for your inputs! Your example may work fine when the action of the form it's the same page, but, when the action is the current page I don't think It's a good idea.

Let me explain better: Let's suppose you have a long contact page with a google map, some text and at the end the contact form (and let's suppose your screen is small and you have to scroll down to see the contact form). Let's also say you are using a simple fade-in / fade-out transition.

Then, at the form submit the user will see the page fade out and the same page fading in, but with a different scroll position.

For a better UX should be your site to manually handle the submission of your form and not Barba.js responsibility.

For example, you may want to just hide the form, display a progress loading and then show the feedback (and maybe scroll to the feedback message to make sure the user will see it).

Making the transition on the whole container at the form submit it looks too much for me. I always use a different behaviour when forms are submitted.

Even if we let the user disable / enable functionality I wonder how many people will actually use it.

For "redirects handling", you meant related to the form submission?

terion-name commented 8 years ago

Then, at the form submit the user will see the page fade out and the same page fading in, but with a different scroll position.

nope. I can use custom (or predefined in package) transition for this:

Barba.Pjax.getTransition = ()=> {
            if (newUrl === oldUrl) {
                 return StaticTransition; // no fade, no scroll change
            }
            return BaseTransition;
        };

Moreover, I'm using such thing now, for simulating tabs: links get data-noscroll="true" attribute and my custom transition doesn't touch the scroll. And scrolls with animation in other case.

Of course, manual form handling is ideal, but It can be said the same for async page changing :) And purpose of this lib is to make this as simple a possible, so handling forms is logical.

For "redirects handling", you meant related to the form submission?

not only. backend can return redirects. xhr resolves them, barba — not. so if I click on /register, backend redirects me to /register/step1, Barba doesn't change url to /register/step1 but should.

luruke commented 8 years ago

Sorry for the late reply @terion-name , I've been quite busy recently. I'll brainstorm a bit about the form thing!

About the redirect handing, thanks! It more looks like a bug, I will check it!

Cheers

cartogram commented 7 years ago

@luruke Barba is great! One pattern that it does not accommodate out of the box is if you want to return the user to the same scroll position. For example, if there is a long feed with links to individual posts and a 'back to feed' link, that when clicked returns them to the feed page at the same scroll position as when they left. There is a likely a way to accomplish this within the current API, so perhaps it is just a matter of putting together another code example in the docs.

maxschulmeister commented 7 years ago

first of all, i really enjoy working with barba.js, thank you for your great effort @luruke It's super easy to understand and use. Maybe theres a way to make binding specific page transition easy. Something like:

Barba.Pjax.getTransition = function(a, b) {
 // first you'd have to define the specific transition that should be fired only from a to b
  return specificTransition;
};

i know you could do something like this easily with conditions, but i think it would make working with barbe.js even nicer if its build in, theres probably also plenty of room to take the idea further.

luruke commented 7 years ago

Thanks for the suggestion @max-schu . I will try to do my best to start v2 next week :)

Cheers

tipsy commented 7 years ago

Hi @luruke,

Thanks for your work, I was about to create the same kind of library, but then I found yours and it seems to work really well! :)

My initial reactions (some may be my mistakes)

luruke commented 7 years ago

Thank you for your precious advices @tipsy!

Forms

Usually, when I have forms on my websites using barba.js I prefer to handle them manually via ajax. But could be an idea.

CSS transitions

It's quite easy if you want to use CSS transitions, you just need to create a basic transition that adds specific CSS classes during the different states of transition. Someone made a little "plugin" (https://github.com/JoeeGrigg/barba-transitions) that can be written better. Maybe I can provide with barba a default transition that adds specific classes.

Prefetch

yes, nice idea.

Polyfill

Strange, I'm including this https://github.com/taylorhakes/promise-polyfill https://github.com/luruke/barba.js/blob/master/src/index.js#L3

Generally I'd like to not add hundreds of features into barba.js, I would like to keep it simple as possible, but still very flexible.

Also one thing that scary me most is to keep the documentation very light without complicating it.

tipsy commented 7 years ago

Usually, when I have forms on my websites using barba.js I prefer to handle them manually via ajax. But could be an idea.

I guess it depends on what you're making. I'm making a native-looking application with user settings (imagine it like android/iphone settings), so posts should feel the same as gets when the user navigates around. I can solve it like @terion-name did, but it would be nice if it worked out of the box. (I realize I'm probably not your target demographic though).

pierrehenri220 commented 7 years ago

Just my two cents: add an auto html head update feature. Right now only the title tag is supported and I'm not the only one who would appreciate :-) I'm currently achieving it like this: https://gist.github.com/pierrehenri220/58690c83d8c8d5c9308a35a240b34d69

And good job for the library. I've just started to enjoy it.
"Nice shapes", amazing piece of codes 💯

tipsy commented 7 years ago

Maybe I can provide with barba a default transition that adds specific classes.

Hi again @luruke,

After playing with Barba some more, I ended up with the classes barba-transition and new-container/old-container, which I use like this:

.barba-transition {
    // shared styles (pos abs, width, etc)
}
.animation-name.new-container {
    // enter animation
}
.animation-name.old-container  {
    // exit animation
}

Maybe it's useful for you. Thanks again for your work on Barba!

luruke commented 7 years ago

@grenouille220 It doesn't make much sense do that to me :) see here: https://github.com/luruke/barba.js/issues/82

@tipsy Thank you!

theamnesic commented 7 years ago

Hi!

Maybe the possibility to add the .no-barba class to a container to ignore all the links inside? The @tipsy data-barba-prefetch could be awesome!

oscarotero commented 7 years ago

Hi. Thanks @luruke for this great project, I've been waiting for something like this for a long time, I even created a little awkward script some time ago, but nothing comparable to barba.js. Some ideas:

I hope you find this useful Happy new year!

luruke commented 7 years ago

Thank you @oscarotero for your inputs!

luruke commented 7 years ago

This weekend I finally started working on this on the branch v2-dev 💪

I mostly worked on the build system / CI:

To have a view of a build process: https://travis-ci.org/luruke/barba.js/builds/192131197

Next steps:

If anyone wants to contribute, will be great if you could try the build process on your machine or help me to write more tests! 🙏🏻

nicooprat commented 7 years ago

Edit: Here's the gist showing what I mean: https://gist.github.com/nicooprat/ea184d51ba3c9ab131bf1d3400ef0ef0

I played a bit with Barba yesterday, and here are the features I'd dream of, and so the structure I'd need. Overall, I think Barba should behave and look more like a router.

Features

Actually all of this is already kinda doable with getTransition, but that could become very messy with a complex website. I think it should be done by the library by default (and only leave to the developer the possibility to overwrite/hook it maybe). I'd prefer a "config over code" behavior here. I tried to achieve this kind of behavior with v1, but the library is not structured for it, so it's really difficult. Here's what I think would be better:

Structure

So internally, Barba would do the following when a link is clicked (speaking of transitions, the rest of the library works fine), pretty similar to the fade transition in the docs does:

  1. Fire the current route out transition (with parameters: next route & a promise to be resolved (getting rid of this.done()) and loads the new URL contents
  2. When those 2 promises are resolved, fire the new route in transition (again with route & promise parameters)
  3. Trigger according events in each step

The move to ES6 is great of course, although I'm not sure including the Promise polyfill is a good idea (in my build tools I already have one, and I don't want to have it included twice): could just declare it as a dep? Speaking of this, I think webpack and others shouldn't be defined in dependencies in your package.json, but rather in devDependencies? A new label v2 for issues would be great too.

Hopefully I can spend some time on v2 in the next few weeks to help. I'll also try to make a quick gist to show what I'd like in a more concrete way. Anyway, I looked at a bunch of other librairies, and I think Barba is the closest to what I need, although the current code structure doesn't really fit for what I'm trying to do.

(Hope I'm clear and thanks for reading me :))

luruke commented 7 years ago

Hello @nicooprat, thanks for taking time to write this.

Router What you are describing i’s very similar to a generic router from a framework/SPA like Vue.js, React, Angular...

Defining routes it’s feasable, but It will introduce certain limitations in my opinion, examples:

Multiple transitions I’m working on a website where I’m using 8 transitions, and it looks fine like this:

  getTransition() {
    if (WorkToDetail.valid()) {
      return WorkToDetail;
    }
    if (HomeAboutToAbout.valid()) {
      return HomeAboutToAbout;
    }
    if (FooterToContact.valid()) {
      return FooterToContact;
    }
    if (FooterContactToContact.valid()) {
      return FooterContactToContact;
    }
    if (HomeSliderToCase.valid()) {
      return HomeSliderToCase;
    }
    if (HomeSliderToPage.valid()) {
      return HomeSliderToPage;
    }
    if (WorkSibling.valid()) {
      return WorkSibling;
    }
    return FadeTransition;
  }

Basically in each transition i’ve added a method .valid that indicate if that transitions can be used or not.

Another example could be this: https://github.com/quentinneyraud/jekyll-starter-kit

As you can see you can easily write your own “structure” around barba.js

GSAP I’d like to keep the library independent, without introducing necessary dependencies.

Promise polyfill You’re right, it’s probably better not include the polyfill in the next version

devDependencies Thank you! I will fix it.

In general, i’d like to keep barba.js very unopinionated,without dictate much the structure of your code

nicooprat commented 7 years ago

What you are describing i’s very similar to a generic router from a framework/SPA like Vue.js, React, Angular...

Indeed, I worked the past few months with Meteor so I'm definitely biased, but I think there're good ideas there and Barba could be the perfect fit between SPA and "regular" websites.

How you will handle situations where you don’t know in advance the page path? Take for example a multilanguage website running wordpress.

To know what's the next route will be, we can match the link href against each route path definition. We could also add something like data-route to the a tag to explicitly tell Barba what the next route is (actually that's what I'm doing now). If we don't know it, the route parameter will be undefined, that's all. To be clear: I don't want Barba to be a full router, just something to progressively enhance the navigation, just like what it is now.

To retrieve an in or out transition, the logic would be:

  1. Check for current route "out" transition and next route "in" transition
  2. If the route is not defined or its in/out transition is not defined, use the default one
  3. If no default transition is defined, just replace old HTML by the new one instantly

The way to match complex URL against the path route definitions might be copied from an existing router. For example, for a multilang site, paths could be something like /[en|fr|it]/posts/*. That would be really great, but maybe for a future release.

What if you want to have “random” transitions? For example create a pool of transitions and pick a random one (it’s certainly not a common case)

In and out transition methods actions are up to the developer. It just needs to resolve the promise. So random transitions are not a problem, being for a specific route or all of them, via the default transitions. We could also still expose the getTransition() method if someone needs to overwrite it for some reason.

I’m working on a website where I’m using 8 transitions, and it looks fine like this:

Actually your example clearly shows what I'd rather avoid :) Could you show what's inside a valid() method? I think you're somehow trying to create something that scale, like what I'm proposing, but sticking to the procedural structure of the current code. What's the advantage?

As you can see you can easily write your own “structure” around barba.js

Yes it's close to what I've in mind (BarbaWrapper and Page are interesting files). But it's really complicated! All this intelligence should be in Barba core IMO. I see no advantage of keeping it outside.

I’d like to keep the library independent, without introducing necessary dependencies.

Of course, that's not what I meant. I was thinking of a optional first-class integration, like the one in Scrollmagic (plugin). But that would be a bonus for a future release too :)

In general, i’d like to keep barba.js very unopinionated, without dictate much the structure of your code

I clearly agree on this, but I think your current code is not really far from what I'm proposing:

All of this is optional in case someone just want a simple fadeIn/fadeOut between all pages ; that could still be done in just a few lines of code. It's not more complicated, just rearranging things in a more scalable/robust/understandable way (IMO).

luruke commented 7 years ago

Thanks @nicooprat, For me the transition can not be determined only by the old route and the next route. (If I understand your vision)

In fact for me a transition can be determined by three factors (by URL, namespace, or the last item clicked), as I explained in this old problem: https://github.com/luruke/barba.js/issues/19#issuecomment-223874845

For example, I might want some sort of transition if I use the top navigation, and a different one if I click on a CTA at the center of the page.

Now of course this has to be managed "manually" (and that is what I am doing in metodo'.valid ', which is not so difficult, but I'm more than happy to explore new ways to simplify this.

I usually work on projects (wordpress), I can not really predict only by URL templates / transition, so this is my doubtful about the routing matching regex.

But I am really interesting to find a solution to simplify the way to choose and declare a transition!

You can open another issue where you can talk about your path proposed? I'm curious to see a test code!

nicooprat commented 7 years ago

Creating a new issue there. Just responding to your last comments here:

For me the transition can not be determined only by the old route and the next route. (If I understand your vision).

That's why every in/out transition methods should receive at least route + eventas parameters (so event.target or event.target.href could be useful). The issue you linked to shows how to currently do it indeed, but I think we can agree that it's pretty messy, like the need to store the clicked element in a global variable.

I usually work on projects (wordpress), I can not really predict only by URL templates / transition, so this is my doubtful about the routing matching regex.

That's my case too. For now, by default, I'm echoing the namespace according to the Wordpress page template. The developer would still be totally free to set a particular namespace for, let's say, a special article that needs some javascript transitions (or even a different onEnter event to initiate a slider). He/she would just have to create a new route js file. We even could let routes extend other routes to only overwrite some of its methods in this case.

How do you currently differentiate URLs to choose a transition? What more than my gist would you wish for a "test code"?

Thanks :)

maxschulmeister commented 7 years ago

another idea that just came to my mind is the option to save the state of the last visited page. I'm aware thats a typical SPA framework functionality, but since barba kind of is the go-to alternative for all devs that dont like/dont want/can't develop an SPA, why not…

what do you think?

nicooprat commented 7 years ago

Barba already exposes history with Barba.HistoryManager.prevStatus() and Barba.HistoryManager.currentStatus() (or full history array with Barba.HistoryManager.history). Is it what you need?

maxschulmeister commented 7 years ago

depends if for example i manipulate the dom through js in the prevstate i'm not sure if the historymanager saves that – didn't test it tho – thanks for the hint.

nicooprat commented 7 years ago

Ok so you mean keeping the actual HTML of the previous views? Kind of overkill for Barba I guess :) But you could do it by listening to events and manually updating the Barba.HistoryManager.history object.

maxschulmeister commented 7 years ago

yes indeed that's what i was talking about. I know… just a thought. I can imagine people end up real quick on this, when building pages with dynamic functionalities like filters sort, etc… But good to know it's kind of possible to achieve that, thanks!

tipsy commented 7 years ago

@max-schu another idea that just came to my mind is the option to save the state of the last visited page ... what do you think?

I don't think barba should attempt to handle state-changes for you. You can solved "edited doms" by persisting the state-change on the backend, or by keeping a separate JS state yourself.

JumpLink commented 7 years ago

I wish me a easy way to replace multiple barba containers in one pajax request with different animations.

Here is an example:

auswahl_353

The screenshot shows a product page with the shopsystem Shopify. On developing themes for Shopify I can not customize the Backend / Codebase of Shopify itself, so it is very limited to use single page applications like angular etc. This is why barba.js is perfect for this.

On Top right (prev, next) you can slide to the next product with a nice animation using barba,js. But normally everything (red, green and blue) slides in the same time with the same animation. It was I very tricky to solve this.

It would be nice if I could define multiple barba containers on the same site to handle the replacement for each container individual. So I would replace the blue and green part without any animation (So it looks as if it does not change) and I the red part with the slide animation.

What do you think about that?

luruke commented 7 years ago

Hello @JumpLink .

No, barba.js do not supports multiple containers. Technically it's possible but it was a design choice.

What you are describing should be feasable with a single transition. You might overlap new and old page then animate the right containers.

tipsy commented 7 years ago

@JumpLink If I understand what you want to do, it's pretty easy to do this with CSS transitions. You put a barba-container on a parent element, position new/old container on top of each other, and do:

.transition .blue {
    animation: none;
}

.transition .red {
    animation: fade-in;
}
JumpLink commented 7 years ago

@luruke and @tipsy thanks for the advice, in a similar way I am solve this currently. Did I understood it correctly, that this feature request would not be an option for barba.js v2? Perhaps a main container and several children's containers would be a way to do this directly through the API for barba.js v2.

Btw: Thank you very much for this great and useful library and the good work!

ghost commented 7 years ago

Hello, i'm start using barba.js and its AWESOME(its really awesome), great work @luruke 👍 . I have a question. I want different page transition on some pages. Eg i want transition NUMBER ONE for aboutpage i want transition NUMBER TWO for projectpage. Is this possible?

luruke commented 7 years ago

@zachariast have a look here: https://github.com/luruke/barba.js/issues/19#issuecomment-223874845

durchanek commented 7 years ago

Hi @luruke and first of all, thank you for all your work here!

I am currently working a new site and decided to use Barba to handle navigation. One of the requests was to replace complete page container for top-level menu items and only subpage container for second-level menu items (with sidebar staying in place). After a bit of testing, I found out this can be solved easily with something like this:

$(document).on('click', '[data-barba=subcontainer]', function(e){
    Barba.Pjax.Dom.containerClass = 'barba-subcontainer';
    Barba.Pjax.Dom.wrapperId = 'barba-subwrapper';
});
$(document).on('click', '[data-barba=container]', function(e){
    Barba.Pjax.Dom.containerClass = 'barba-container';
    Barba.Pjax.Dom.wrapperId = 'barba-wrapper';
});

But what would be really nice is to have the option to define multiple Barba instances instead of configuring static class. This would also allow per-instance transitions.

lsbyerley commented 7 years ago

Love the framework! Couple things I'd like added..

JumpLink commented 7 years ago

Offline-Support for the Barba Cache would be also nice for Barba.js v2

mikehwagz commented 7 years ago

One of my favorite aspects of Barba is that it does not behave like a typical router in that you do not need to define routes. This makes it incredibly simple to drop into a project. Having used a framework like Bigwheel from Jam3 on many projects, I've realized how limiting the need to define routes can be for a large site with many dynamic routes (like a WordPress site). Hoping V2 keeps the simplicity of V1.

bramcordie commented 7 years ago

@lsbyerley What's your use-case for detecting a back/forward button press and where do you want to know this?

Using the existing API and some listeners it is possible to differentiate between the user following a link or navigating the browser history. The latter is caused by a popstate event. Barba starts listening to this event when you call start() on Barba.Pjax. The following example shows how you can use the event to know how the user navigated while transitioning.

var popping = false;

window.addEventListener('popstate', function () {
  popping = true;
});

Barba.Pjax.start();

Barba.Dispatcher.on('initStateChange', function() {
  popping = false;
});

Barba.Pjax.getTransition = function() {
  return popping ? HideShowTransition : FadeTransition;
};

Disabling animations on transitions triggered by popstate is very useful if you don't want Safari to glitch when using Swipe between pages on macOS. Unfortunately the Barba documentation does not take this into consideration in the FadeTransition Example and the API does not allow to detect it out-of-the-box. Because of this a lot of websites that use animated transitions, including the Barba examples, are very unpleasant to navigate when using swipe gestures or mouse hotkeys.

lsbyerley commented 7 years ago

@bramcordie Thanks for the explanation. I'm adding an is-active class to my nav links when linkClicked is triggered. If you press the back button, this is never fired and the nav links don't show correct active link.

bramcordie commented 7 years ago

Hey @lsbyerley, our use-case are completely different but I think I can help you out.

Instead of listening to linkClicked you can switch to initStateChange. This event might not give you the element that was clicked but the currentStatus argument is enough to get the current URL and update your navigation.

Below is some example code. You might need to change the nav and a queries, have fun 😎

Barba.Dispatcher.on('initStateChange', function(currentStatus) {
  $('nav').find('a').each(function() {
    $(this).toggleClass('is-active', $(this).href === currentStatus.url);
  });
});

@luruke I don't think the source of the official docs are public so I can't send a pull request to add this example? I'm not sure where it belongs but you might consider adding it under http://barbajs.org/faq.html?

lsbyerley commented 7 years ago

Hey @bramcordie thanks man this works great and solves the back/forward issue!

nelsonswork commented 6 years ago

@bramcordie thanks this is great. How can I trigger the transitions on page load?