Reagir - Exibir a tela de carregamento enquanto o DOM está renderizando?

150

Este é um exemplo da página do aplicativo Google Adsense. A tela de carregamento exibida antes da página principal foi exibida depois.

insira a descrição da imagem aqui

Não sei como fazer a mesma coisa com o React, porque se eu fizer a tela de carregamento renderizada pelo componente React, ela não será exibida enquanto a página estiver carregando, pois precisará aguardar o DOM renderizado anteriormente.

Atualizada :

Fiz um exemplo da minha abordagem colocando o carregador de tela index.htmle removendo-o no ReactcomponentDidMount() método do ciclo de vida do .

Exemplo e tela de carregamento e reação .

Thanh Nguyen
fonte
Mostre o que deseja mostrar em js comuns e oculte-o ou remova-o do DOM quando o reagir estiver montado. Tudo que você precisa fazer é ocultá-lo do código de reação.
FurkanO
Isso é simplesmente maravilhoso! Obrigado.
Arman Karimi 18/03

Respostas:

100

Isso pode ser feito colocando o ícone de carregamento no seu arquivo html (index.html para ex), para que os usuários vejam o ícone imediatamente após o carregamento do arquivo html.

Quando o aplicativo termina o carregamento, você pode simplesmente remover esse ícone de carregamento em um gancho do ciclo de vida, geralmente faço isso componentDidMount.

kkkkkkk
fonte
11
Se você montar o componente raiz no nó pai desse ícone, não será necessário removê-lo manualmente. O React limpa os filhos do nó de montagem e coloca seu próprio DOM recém-renderizado lá.
rishat
6
Eu não colocar o ícone dentro do nó raiz Reagir aplicativo, ele simplesmente não parece certo para mim
kkkkkkk
171

O objetivo

Quando a página html for renderizada, exiba um botão giratório imediatamente (enquanto o React carrega) e oculte-o depois que o React estiver pronto.

Como o girador é renderizado em HTML / CSS puro (fora do domínio React), o React não deve controlar diretamente o processo de exibição / ocultação, e a implementação deve ser transparente ao React.

Solução 1 - a: pseudo classe vazia

Como você processa o reagir em um contêiner DOM - <div id="app"></div>, você pode adicionar um giratório a esse contêiner e, quando o reagir for carregado e renderizado, o girador desaparecerá.

Você não pode adicionar um elemento DOM (uma div, por exemplo) dentro da raiz do reag, pois o React substituirá o conteúdo do contêiner assim que ReactDOM.render()for chamado. Mesmo se você renderizar null, o conteúdo ainda será substituído por um comentário - <!-- react-empty: 1 -->. Isso significa que, se você deseja exibir o carregador enquanto o componente principal monta, os dados estão sendo carregados, mas nada é renderizado, uma marcação do carregador colocada dentro do contêiner (<div id="app"><div class="loader"></div></div> por exemplo) não funcionaria.

Uma solução alternativa é adicionar a classe giratória ao contêiner de reação e usar a :emptypseudo classe . O botão giratório ficará visível, desde que nada seja renderizado no contêiner (os comentários não contam). Assim que a reação renderizar algo diferente de comentar, o carregador desaparecerá.

Exemplo 1

No exemplo, você pode ver um componente que é renderizado nullaté que esteja pronto. O contêiner também é o carregador - <div id="app" class="app"></div>e a classe do carregador só funcionará se for :empty(veja os comentários no código):

Exemplo 2

Uma variação no uso da :emptypseudo classe para mostrar / ocultar um seletor está configurando o botão giratório como um elemento irmão para o contêiner do aplicativo e mostrando-o enquanto o contêiner estiver vazio usando o combinador de irmãos adjacente ( +):


Solução 2 - Passe "manipuladores" giratórios como acessórios

Para ter um controle mais refinado sobre o estado de exibição dos giradores, crie duas funções showSpinnerehideSpinner , e passá-las para o recipiente raiz via adereços. As funções podem manipular o DOM ou fazer o que for necessário para controlar o controle giratório. Dessa maneira, o React não está ciente do "mundo exterior", nem precisa controlar o DOM diretamente. Você pode substituir facilmente as funções para teste ou, se precisar alterar a lógica, e pode passá-las para outros componentes na árvore do React.

Exemplo 1

Exemplo 2 - ganchos

Este exemplo usa o useEffectgancho para ocultar o botão giratório após a montagem do componente.

Ori Drori
fonte
Você poderia esclarecer onde devem estar as duas últimas seções de código? O primeiro está claramente no arquivo src javascript para o componente react, e o terceiro, acho que vai no modelo html a ser renderizado pelo referido arquivo js, ​​mas para onde vai o segundo?
precisa saber é o seguinte
1
O segundo é o CSS. Eu usei CSS global, mas você pode usar Módulos CSS ou CSS em JS. O terceiro é o arquivo HTML, que pode incluir a marcação giratória, se necessário (segundo exemplo).
Ori Drori
Esse tempo limite não é bom quando o desempenho é levado em consideração.
dryleaf
4
@dryleaf - o setTimeout não faz parte da solução. Ele simula a espera de uma ação assíncrona antes de renderizar o conteúdo.
Ori Drori #
Eu uso abordagem semelhante. Não consigo encontrar nada no webpack que possa me ajudar a interromper o cache do arquivo css necessário para o carregador. Você pode ajudar?
hamza-jutt
40

A solução alternativa para isso é:

Na sua função de renderização, faça algo assim:

constructor() {
    this.state = { isLoading: true }
}

componentDidMount() {
    this.setState({isLoading: false})
}

render() {
    return(
        this.state.isLoading ? *showLoadingScreen* : *yourPage()*
    )
}

Inicialize isLoading como true no construtor e false em componentDidMount

Amoolya S Kumar
fonte
Quando chamamos o método ajax para carregar dados nos componentes filhos. componentDidMount chamado antes do preenchimento dos dados do componente filho. Como superamos esse tipo de problema?
dush88c
2
Para o Mounting Life cyle, tudo bem, você gostaria de adicionar algo para o ciclo de vida da atualização?
zakir
tenho que fazer isso em todas as páginas ou apenas na entrada do aplicativo
Pedro JR
16

Se alguém que procura uma biblioteca drop-in, configuração zero e dependência zero para o caso de uso acima, tente pace.js ( http://github.hubspot.com/pace/docs/welcome/ ).

Ele se conecta automaticamente a eventos (ajax, readyState, history pushstate, loop de eventos js etc.) e mostra um carregador personalizável.

Funcionou bem com nossos projetos de reagir / retransmitir (lida com alterações de navegação usando reat -router, solicitações de retransmissão) (Não afiliado; havia usado o pace.js em nossos projetos e funcionou muito bem)

Hafiz Ismail
fonte
Ei! Você pode me dizer como usá-lo com o react?
uneet7
basta anexar o script public/index.htmle escolher um estilo. isso é absolutamente simples, plugin incrível. obrigado.
PJ3
Eu não teria encontrado ritmo sem essa resposta. Era tão fácil de incluir e, com um pouco de mágica CSS e alguns anexos de eventos, fui capaz de bloquear / desativar o aplicativo durante as transições e personalizar o botão giratório.
invertedSpear
12

Quando o aplicativo React é massivo, leva muito tempo para que ele funcione após a página ser carregada. Digamos que você monte sua parte do React no aplicativo #app. Normalmente, esse elemento no seu index.html é simplesmente uma div vazia:

<div id="app"></div>

O que você pode fazer é colocar um pouco de estilo e um monte de imagens para melhorar a aparência entre o carregamento da página e a renderização inicial do aplicativo React no DOM:

<div id="app">
  <div class="logo">
    <img src="/my/cool/examplelogo.svg" />
  </div>
  <div class="preload-title">
    Hold on, it's loading!
  </div>
</div>

Após o carregamento da página, o usuário verá imediatamente o conteúdo original de index.html. Logo após, quando o React estiver pronto para montar toda a hierarquia de componentes renderizados neste nó DOM, o usuário verá o aplicativo real.

Nota class não className. É porque você precisa colocar isso no seu arquivo html.


Se você usa o SSR, as coisas ficam menos complicadas porque o usuário realmente vê o aplicativo real logo após o carregamento da página.

rishat
fonte
Isso funciona também tenho dois lugares onde o carregamento acontece. Um é o aplicativo massivo. e a seguir, a preparação (montagem de vários componentes). Então, recebo uma etapa intermitente porque o app.render assume o controle e a animação é redefinida ( substituída de verdade.) Haveria uma maneira de evitar esse flash? O React comparará o DOM um a um? Mas pelo que eu entendo Reagir adiciona todos os tipos de dados privados nas tags ...
Alexis Wilke
12

Isso acontecerá antes de ReactDOM.render()assumir o controle da raiz <div> . Ou seja, seu aplicativo não terá sido montado até esse ponto.

Então você pode adicionar seu carregador no seu index.htmlarquivo dentro da raiz<div> . E isso ficará visível na tela até o React assumir o controle.

Você pode usar qualquer elemento do carregador que funcione melhor para você ( svgcom animação, por exemplo).

Você não precisa removê-lo em nenhum método de ciclo de vida. O React substituirá todos os filhos de sua raiz <div> pelo seu renderizado <App/>, como podemos ver no GIF abaixo.

Exemplo no CodeSandbox

insira a descrição da imagem aqui

index.html

<head>
  <style>
    .svgLoader {
      animation: spin 0.5s linear infinite;
      margin: auto;
    }
    .divLoader {
      width: 100vw;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
  </style>
</head>

<body>
  <div id="root">
    <div class="divLoader">
      <svg class="svgLoader" viewBox="0 0 1024 1024" width="10em" height="10em">
        <path fill="lightblue"
          d="PATH FOR THE LOADER ICON"
        />
      </svg>
    </div>
  </div>
</body>

index.js

Usando debuggerpara inspecionar a página antes da ReactDOM.render()execução.

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

debugger; // TO INSPECT THE PAGE BEFORE 1ST RENDER

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
cbdeveloper
fonte
uma solução bonita e elegante
Gal Margalit
1
Estou feliz que ajuda!
Cbdeveloper 23/05/19
9

Hoje em dia também podemos usar ganchos no React 16.8:

import React, { useState, useEffect } from 'react';

const App = () => {
  const [ spinner, setSpinner ] = useState(true);

  // It will be executed before rendering

  useEffect(() => {
    setTimeout(() => setSpinner(false), 1000)
  }, []);

  // [] means like componentDidMount

  return !spinner && <div>Your content</div>;
};

export default App;
Max Kalik
fonte
5

Definir o tempo limite em componentDidMount funciona, mas no meu aplicativo recebi um aviso de vazamento de memória. Tente algo assim.

constructor(props) {
    super(props)
    this.state = { 
      loading: true,
    }
  }
  componentDidMount() {
    this.timerHandle = setTimeout(() => this.setState({ loading: false }), 3500); 
  }

  componentWillUnmount(){
    if (this.timerHandle) {
      clearTimeout(this.timerHandle);
      this.timerHandle = 0;
    }
  }
Rich Costello
fonte
4

Eu tive que lidar com esse problema recentemente e encontrei uma solução, que funciona muito bem para mim. No entanto, tentei a solução @Ori Drori acima e, infelizmente, não funcionou corretamente (houve alguns atrasos + não gosto do uso desetTimeout função).

Isto é o que eu vim com:

index.html Arquivo

headEtiqueta interna - estilos para o indicador:

<style media="screen" type="text/css">

.loading {
  -webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
  animation: sk-scaleout 1.0s infinite ease-in-out;
  background-color: black;
  border-radius: 100%;
  height: 6em;
  width: 6em;
}

.container {
  align-items: center;
  background-color: white;
  display: flex;
  height: 100vh;
  justify-content: center;
  width: 100vw;
}

@keyframes sk-scaleout {
  0% {
    -webkit-transform: scale(0);
    transform: scale(0);
  }
  100% {
    -webkit-transform: scale(1.0);
    opacity: 0;
    transform: scale(1.0);
  }
}

</style>

Agora a bodytag:

<div id="spinner" class="container">
  <div class="loading"></div>
</div>

<div id="app"></div>

E então vem uma lógica muito simples, dentro do app.jsarquivo (na função render):

const spinner = document.getElementById('spinner');

if (spinner && !spinner.hasAttribute('hidden')) {
  spinner.setAttribute('hidden', 'true');
}

Como isso funciona?

Quando o primeiro componente (no meu aplicativo, app.jstambém na maioria dos casos) é montado corretamente, ele spinnerfica oculto com a aplicação do hiddenatributo.

O que é mais importante adicionar - a !spinner.hasAttribute('hidden')condição evita adicionar hiddenatributo ao girador a cada montagem do componente; portanto, ele será adicionado apenas uma vez, quando o aplicativo inteiro for carregado.

usuário gentil
fonte
4

Estou usando o pacote react -progress-2 npm, que é de dependência zero e funciona muito bem no ReactJS.

https://github.com/milworm/react-progress-2

Instalação:

npm install react-progress-2

Inclua react-progress-2 / main.css no seu projeto.

import "node_modules/react-progress-2/main.css";

Inclua react-progress-2e coloque-o em algum lugar do componente superior, por exemplo:

import React from "react";
import Progress from "react-progress-2";

var Layout = React.createClass({
render: function() {
    return (
        <div className="layout">
            <Progress.Component/>
                {/* other components go here*/}
            </div>
        );
    }
});

Agora, sempre que precisar exibir um indicador, basta ligar Progress.show(), por exemplo:

loadFeed: function() {
    Progress.show();
    // do your ajax thing.
},

onLoadFeedCallback: function() {
    Progress.hide();
    // render feed.
}

Observe que as chamadas showe hidesão empilhadas; portanto, após as chamadas de apresentação n-consecutivas, você precisa n ocultar as chamadas para ocultar um indicador ou pode usar Progress.hideAll().

Alex Zavrazhniy
fonte
4

Também estou usando o React no meu aplicativo. Para pedidos que estou usando axios interceptors, a melhor maneira de fazer a tela do carregador (página inteira, como você mostrou um exemplo) é adicionar classe ou ID ao corpo, por exemplo, dentro dos interceptores (aqui, código da documentação oficial com algum código personalizado):

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
     document.body.classList.add('custom-loader');
     return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
       document.body.classList.remove('custom-loader');
       return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  }); 

E, em seguida, basta implementar no CSS seu carregador com pseudoelementos (ou adicionar classe ou ID a um elemento diferente, não o corpo que você quiser) - você pode definir a cor do plano de fundo como opaca ou transparente, etc ... Exemplo:

custom-loader:before {
    background: #000000;
    content: "";
    position: fixed;
    ...
}

custom-loader:after {
    background: #000000;
    content: "Loading content...";
    position: fixed;
    color: white;
    ...
}
adrian95999
fonte
3

Edite o local do arquivo index.html na pasta pública . Copie sua imagem para o mesmo local que index.html na pasta pública. E, em seguida, substitua a parte do conteúdo de index.html contendo <div id="root"> </div>tags pelo código html fornecido abaixo.

<div id="root">  <img src="logo-dark300w.png" alt="Spideren" style="vertical-align: middle; position: absolute;
   top: 50%;
   left: 50%;
   margin-top: -100px; /* Half the height */
   margin-left: -250px; /* Half the width */" />  </div>

O logotipo agora aparecerá no meio da página durante o processo de carregamento. E será substituído após alguns segundos pelo React.

Magnus Melwin
fonte
2

Você não precisa de muito esforço, aqui está um exemplo básico.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="theme-color" content="#000000" />
  <meta name="description" content="Web site created using create-react-app" />
  <link rel="apple-touch-icon" href="logo192.png" />
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <title>Title</title>
  <style>
    body {
      margin: 0;
    }

    .loader-container {
      width: 100vw;
      height: 100vh;
      display: flex;
      overflow: hidden;
    }

    .loader {
      margin: auto;
      border: 5px dotted #dadada;
      border-top: 5px solid #3498db;
      border-radius: 50%;
      width: 100px;
      height: 100px;
      -webkit-animation: spin 2s linear infinite;
      animation: spin 2s linear infinite;
    }

    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }

      100% {
        -webkit-transform: rotate(360deg);
      }
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }

  </style>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root">
    <div class="loader-container">
      <div class="loader"></div>
    </div>
  </div>
</body>

</html>

Você pode brincar HTMLe CSSfazer parecer o seu exemplo.

Ahmed Kamal
fonte
1

A pergunta mais importante é: o que você quer dizer com 'carregar'? Se você está falando sobre o elemento físico que está sendo montado, algumas das primeiras respostas aqui são ótimas. No entanto, se a primeira coisa que seu aplicativo faz é verificar a autenticação, o que você realmente está carregando são dados do back-end, independentemente de o usuário ter passado por um cookie que os rotula como usuário autorizado ou não autorizado.

Isso se baseia no redux, mas você pode alterá-lo facilmente para o modelo de estado de reação simples.

criador de ação:

export const getTodos = () => {
  return async dispatch => {
    let res;
    try {
      res = await axios.get('/todos/get');

      dispatch({
        type: AUTH,
        auth: true
      });
      dispatch({
        type: GET_TODOS,
        todos: res.data.todos
      });
    } catch (e) {
    } finally {
      dispatch({
        type: LOADING,
        loading: false
      });
    }
  };
};

A parte final significa que, se o usuário é ou não autorizado, a tela de carregamento desaparece após o recebimento de uma resposta.

Aqui está a aparência de um componente que carrega:

class App extends Component {
  renderLayout() {
    const {
      loading,
      auth,
      username,
      error,
      handleSidebarClick,
      handleCloseModal
    } = this.props;
    if (loading) {
      return <Loading />;
    }
    return (
      ...
    );
  }

  ...

  componentDidMount() {
    this.props.getTodos();
  }

...

  render() {
    return this.renderLayout();
 }

}

Se state.loading for verdadeiro, sempre veremos uma tela de carregamento. Em componentDidMount, chamamos nossa função getTodos, que é um criador de ações que transforma state.loading em falsy quando obtemos uma resposta (o que pode ser um erro). Nosso componente é atualizado, as chamadas são renderizadas novamente e, desta vez, não há tela de carregamento devido à instrução if.

user3605834
fonte
1

O início do aplicativo react é baseado no download do pacote principal. O aplicativo React é iniciado somente após o download do pacote principal no navegador. Isso é verdade mesmo no caso de arquitetura de carregamento lento. Mas o fato é que não podemos indicar exatamente o nome de nenhum pacote. Como o webpack adicionará um valor de hash no final de cada pacote configurável no momento em que você executa o comando 'npm run build'. É claro que podemos evitar isso alterando as configurações de hash, mas isso afetará seriamente o problema de dados em cache no navegador. Os navegadores podem não aceitar a nova versão devido ao mesmo nome de pacote. . precisamos de uma abordagem webpack + js + CSS para lidar com essa situação.

altere public / index.html como abaixo

<!DOCTYPE html>
<html lang="en" xml:lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=3.0, shrink-to-fit=no">
  <meta name="theme-color" content="#000000">
  <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
  <style>
 .percentage {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 150px;
      height: 150px;
      border: 1px solid #ccc;
      background-color: #f3f3f3;
      -webkit-transform: translate(-50%, -50%);
          -ms-transform: translate(-50%, -50%);
              transform: translate(-50%, -50%);
      border: 1.1em solid rgba(0, 0, 0, 0.2);
      border-radius: 50%;
      overflow: hidden;
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-pack: center;
          -ms-flex-pack: center;
              justify-content: center;
      -webkit-box-align: center;
          -ms-flex-align: center;
              align-items: center;
    }

    .innerpercentage {
      font-size: 20px;
    }
  </style>
  <script>
    function showPercentage(value) {
      document.getElementById('percentage').innerHTML = (value * 100).toFixed() + "%";
    }
    var req = new XMLHttpRequest();
    req.addEventListener("progress", function (event) {
      if (event.lengthComputable) {
        var percentComplete = event.loaded / event.total;
        showPercentage(percentComplete)
        // ...
      } else {
        document.getElementById('percentage').innerHTML = "Loading..";
      }
    }, false);

    // load responseText into a new script element
    req.addEventListener("load", function (event) {
      var e = event.target;
      var s = document.createElement("script");
      s.innerHTML = e.responseText;
      document.documentElement.appendChild(s);
      document.getElementById('parentDiv').style.display = 'none';

    }, false);

    var bundleName = "<%= htmlWebpackPlugin.files.chunks.main.entry %>";
    req.open("GET", bundleName);
    req.send();

  </script>
  <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->

  <title>App Name</title>
  <link href="<%= htmlWebpackPlugin.files.chunks.main.css[0] %>" rel="stylesheet">
</head>

<body>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <div id="parentDiv" class="percentage">
    <div id="percentage" class="innerpercentage">loading</div>
  </div>
  <div id="root"></div>
  <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
</body>

</html>

Na configuração do webpack de produção, altere a opção HtmlWebpackPlugin para abaixo

 new HtmlWebpackPlugin({
          inject: false,
...

Pode ser necessário usar o comando 'ejetar' para obter o arquivo de configuração. o webpack mais recente pode ter a opção de configurar o HtmlWebpackPlugin sem ejetar o projeto. insira a descrição da imagem aqui

Anoop Chillayi Kochappu
fonte
1

Também usei a resposta de @Ori Drori e consegui fazê-la funcionar. À medida que o código do React aumenta, os pacotes configuráveis ​​também são compilados para que o navegador do cliente precise fazer o download no primeiro acesso. Isso impõe um problema de experiência do usuário se você não lidar bem com isso.

O que eu adicionei à resposta do @Ori foi adicionar e executar a função onload no atributo index.html on onload da tag body, para que o carregador desapareça depois que tudo estiver totalmente carregado na navegação, veja o trecho abaixo:

<html>
  <head>
     <style>
       .loader:empty {
          position: absolute;
          top: calc(50% - 4em);
          left: calc(50% - 4em);
          width: 6em;
          height: 6em;
          border: 1.1em solid rgba(0, 0, 0, 0.2);
          border-left: 1.1em solid #000000;
          border-radius: 50%;
          animation: load8 1.1s infinite linear;
        }
        @keyframes load8 {
          0% {
           transform: rotate(0deg);
          }
          100% {
           transform: rotate(360deg);
          }
        }
     </style>
     <script>
       function onLoad() {
         var loader = document.getElementById("cpay_loader");loader.className = "";}
     </script>
   </head>
   <body onload="onLoad();">
     more html here.....
   </body>
</html>
Joseph Tabajjwa
fonte
1

Que tal usar o ritmo

Use este endereço de link aqui.

https://github.hubspot.com/pace/docs/welcome/

1.No site deles, selecione o estilo que deseja e cole em index.css

2.go to cdnjs Copie o link para Pace Js e adicione às tags de script em public / index.html

Detecta automaticamente as cargas da Web e exibe o ritmo na parte superior do navegador.

Você também pode modificar a altura e a animação no css também.

roqkabel
fonte
Impressionante e pode ser integrado rapidamente.
UzumakiL 16/06